<template>
    <!-- 图片上传对话框 -->
    <v-dialog v-model="dialog" max-width="800px" persistent>
        <v-card>
            <v-card-title class="text-h5">
                {{ options.title || '上传头像' }}
            </v-card-title>

            <v-card-text>
                <div class="upload-container">
                    <!-- 文件上传区域 -->
                    <div v-if="!imageFile" class="upload-area" @drop.prevent="handleDrop" @dragover.prevent
                        @dragenter.prevent @click="triggerFileInput">
                        <v-icon size="48" color="grey-lighten-1">mdi-cloud-upload</v-icon>
                        <div class="text-body-1 mt-2">点击或拖拽图片到此处</div>
                        <div class="text-caption text-grey">
                            支持 JPG、PNG 格式，最大 {{ options.maxSize || 5 }}MB
                        </div>
                    </div>

                    <!-- 图片裁剪区域 -->
                    <div v-if="imageFile" class="cropper-container">
                        <div class="cropper-wrapper">
                            <div ref="cropperCanvasWrapper" class="cropper-canvas-wrapper" :style="{
                                width: '400px',
                                height: '400px'
                            }"></div>
                        </div>

                        <div class="preview-container mt-4">
                            <div class="text-subtitle-2 mb-2">预览效果:</div>
                            <div class="preview-box d-flex justify-center" :style="{
                                width: Math.min(options.width || 200, 200) + 'px',
                                height: Math.min(options.height || 200, 200) + 'px',
                                borderRadius: '50%'
                            }">
                                <canvas ref="previewCanvas"></canvas>
                            </div>
                        </div>
                    </div>

                    <!-- 隐藏的文件输入 -->
                    <input ref="fileInput" type="file" accept="image/*" style="display: none"
                        @change="handleFileSelect" />
                </div>
            </v-card-text>

            <v-card-actions>
                <v-spacer></v-spacer>
                <v-btn color="grey" variant="text" :disabled="uploading" @click="cancel">
                    取消
                </v-btn>
                <v-btn v-if="imageFile" color="grey" variant="text" :disabled="uploading" @click="resetImage">
                    重新选择
                </v-btn>
                <v-btn color="primary" variant="flat" :disabled="!imageFile || uploading" :loading="uploading"
                    @click="confirmUpload">
                    {{ uploading ? '上传中...' : '确认上传' }}
                </v-btn>
            </v-card-actions>
        </v-card>
    </v-dialog>
</template>

<script setup lang="ts">
import { ref, nextTick, onUnmounted } from 'vue'
// 按照官方文档，直接导入cropperjs来自动注册所有Web Components
import 'cropperjs'
import { doUpload, type UploadResultModel } from '@/api/tool/ossTool'
import { type ResponseData } from '@/utils/request'
import { useMessage } from '@/composables/useMessage';
const { success: showSuccess, error: showError } = useMessage();


interface UploadOptions {
    title?: string
    width?: number
    height?: number
    maxSize?: number // 最大文件大小(MB)
    autoUpload?: boolean // 是否自动上传到服务器
}


const dialog = ref(false)
const options = ref<UploadOptions>({})
const imageFile = ref<File | null>(null)
const imagePreview = ref('')
const cropperCanvasWrapper = ref<HTMLElement>()
const previewCanvas = ref<HTMLCanvasElement>()
const fileInput = ref<HTMLInputElement>()
const uploading = ref(false)

let resolvePromise: ((value: UploadResultModel | null) => void) | null = null

// 打开对话框
const open = (uploadOptions: UploadOptions = {}): Promise<UploadResultModel | null> => {
    return new Promise((resolve) => {
        options.value = uploadOptions
        resolvePromise = resolve
        dialog.value = true
    })
}

// 格式化文件大小
const formatFileSize = (bytes: number): string => {
    if (bytes < 1024) return bytes + ' B'
    if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'
    return (bytes / (1024 * 1024)).toFixed(1) + ' MB'
}

// 触发文件选择
const triggerFileInput = () => {
    fileInput.value?.click()
}

// 处理文件选择
const handleFileSelect = (event: Event) => {
    const target = event.target as HTMLInputElement
    const file = target.files?.[0]
    if (file) {
        processFile(file)
    }
}

// 处理拖拽文件
const handleDrop = (event: DragEvent) => {
    const files = event.dataTransfer?.files
    if (files && files.length > 0) {
        processFile(files[0])
    }
}

// 处理文件
const processFile = (file: File) => {
    // 检查文件类型
    if (!file.type.startsWith('image/')) {
        alert('请选择图片文件')
        return
    }

    // 检查文件大小 - maxSize以MB为单位
    const maxSizeMB = options.value.maxSize || 5
    const maxSizeBytes = maxSizeMB * 1024 * 1024
    console.log('file.size', file.size)
    console.log('maxSizeBytes', maxSizeBytes)
    if (file.size > maxSizeBytes) {
        alert(`文件大小不能超过 ${maxSizeMB}MB`)
        return
    }

    imageFile.value = file

    // 创建预览
    const reader = new FileReader()
    reader.onload = (e) => {
        imagePreview.value = e.target?.result as string
        nextTick(() => {
            initCropper()
        })
    }
    reader.readAsDataURL(file)
}

// 初始化裁剪器 - 使用官方文档的Web Components方式
const initCropper = () => {
    if (!cropperCanvasWrapper.value || !imagePreview.value) return

    const width = options.value.width || 200
    const height = options.value.height || 200
    const aspectRatio = width / height

    // 清空容器
    cropperCanvasWrapper.value.innerHTML = ''

    // 根据官方文档创建Web Components结构
    const cropperHTML = `
        <cropper-canvas background class="h-100">
            <cropper-image 
                src="${imagePreview.value}" 
                alt="裁剪图片" 
                rotatable 
                scalable 
                skewable 
                translatable>
            </cropper-image>
            <cropper-shade hidden></cropper-shade>
            <cropper-handle action="select" plain></cropper-handle>
            <cropper-selection 
                aspect-ratio="${aspectRatio}"
                initial-coverage="0.8" 
                movable 
                resizable
                outlined>
                <cropper-grid role="grid" bordered covered></cropper-grid>
                <cropper-crosshair centered></cropper-crosshair>
                <cropper-handle action="move" theme-color="rgba(255, 255, 255, 0.35)"></cropper-handle>
                <cropper-handle action="n-resize"></cropper-handle>
                <cropper-handle action="e-resize"></cropper-handle>
                <cropper-handle action="s-resize"></cropper-handle>
                <cropper-handle action="w-resize"></cropper-handle>
                <cropper-handle action="ne-resize"></cropper-handle>
                <cropper-handle action="nw-resize"></cropper-handle>
                <cropper-handle action="se-resize"></cropper-handle>
                <cropper-handle action="sw-resize"></cropper-handle>
            </cropper-selection>
        </cropper-canvas>
    `

    // 插入HTML
    cropperCanvasWrapper.value.innerHTML = cropperHTML

    // 等待Web Components完全初始化
    setTimeout(() => {
        console.log('开始查找裁剪组件...')
        const canvas = cropperCanvasWrapper.value!.querySelector('cropper-canvas') as any
        const selection = cropperCanvasWrapper.value!.querySelector('cropper-selection') as any

        console.log('找到的组件:', { canvas, selection })

        if (selection) {
            console.log('设置裁剪监听器')
            selection.addEventListener('change', updatePreview)
            // 初始更新预览
            setTimeout(updatePreview, 100)
        } else {
            console.error('未找到cropper-selection元素')
        }
    }, 500)
}

// 更新预览
const updatePreview = async () => {
    if (!cropperCanvasWrapper.value || !previewCanvas.value) return

    const selection = cropperCanvasWrapper.value.querySelector('cropper-selection') as any
    if (!selection) return

    try {
        const canvas = await selection.$toCanvas({
            width: options.value.width || 200,
            height: options.value.height || 200
        })

        const previewCtx = previewCanvas.value.getContext('2d')
        const previewWidth = Math.min(options.value.width || 200, 200)
        const previewHeight = Math.min(options.value.height || 200, 200)

        previewCanvas.value.width = previewWidth
        previewCanvas.value.height = previewHeight

        if (previewCtx && canvas) {
            previewCtx.clearRect(0, 0, previewWidth, previewHeight)
            previewCtx.drawImage(canvas, 0, 0, previewWidth, previewHeight)
        }
    } catch (error) {
        console.error('更新预览失败:', error)
    }
}

// 确认上传
const confirmUpload = async () => {
    if (!cropperCanvasWrapper.value || !imageFile.value) return

    const selection = cropperCanvasWrapper.value.querySelector('cropper-selection') as any
    if (!selection) return

    try {
        uploading.value = true

        const canvas = await selection.$toCanvas({
            width: options.value.width || 200,
            height: options.value.height || 200
        })

        // 转换为blob
        const blob = await new Promise<Blob>((resolve) => {
            canvas.toBlob((blob: Blob | null) => {
                if (blob) {
                    resolve(blob)
                }
            }, imageFile.value!.type, 0.9)
        })

        const croppedFile = new File([blob], imageFile.value.name, {
            type: imageFile.value.type,
            lastModified: Date.now()
        })

        let result: UploadResultModel = {
            fileStoragePath: '',
            name: '',
            nameAndSuffix: '',
            prefix: '',
            randomFileName: '',
            randomFileNameAndSuffix: '',
            size: 0,
            suffix: ''
        }

        // 如果启用自动上传，则上传到服务器
        if (options.value.autoUpload !== false) {
            console.log('开始上传到服务器...')

            const formData = new FormData()
            formData.append('file', croppedFile)

            try {
                const { msg, data, code } = await doUpload(formData)
                if (code === 0) {
                    showSuccess(msg)
                    result = data
                } else {
                    showError(msg)
                }
            } catch (uploadError) {
                console.error('上传失败:', uploadError)
                showError('图片上传失败，请重试 ' + uploadError)
                return
            } finally {
                close(result)
                return result
            }
        }
    } catch (error) {
        console.error('生成裁剪图片失败:', error)
        showError('图片上传失败，请重试 ' + error)
    } finally {
        uploading.value = false
    }
}

// 重新选择图片
const resetImage = () => {
    imageFile.value = null
    imagePreview.value = ''
    if (cropperCanvasWrapper.value) {
        cropperCanvasWrapper.value.innerHTML = ''
    }
    if (fileInput.value) {
        fileInput.value.value = ''
    }
}

// 取消
const cancel = () => {
    close(null)
}

// 关闭对话框
const close = (result: UploadResultModel | null) => {
    dialog.value = false
    resetImage()
    if (resolvePromise) {
        resolvePromise(result)
        resolvePromise = null
    }
}

// 清理资源
onUnmounted(() => {
    resetImage()
})

// 暴露方法
defineExpose({
    open
})
</script>

<style scoped>
.upload-container {
    min-height: 400px;
}

.upload-area {
    border: 2px dashed #ccc;
    border-radius: 8px;
    padding: 60px 20px;
    text-align: center;
    cursor: pointer;
    transition: border-color 0.3s;
}

.upload-area:hover {
    border-color: #1976d2;
}

.cropper-container {
    display: flex;
    gap: 20px;
    align-items: flex-start;
}

.cropper-wrapper {
    flex: 1;
}

.cropper-canvas-wrapper {
    border: 1px solid #ddd;
    border-radius: 8px;
    overflow: hidden;
}

.preview-container {
    flex-shrink: 0;
    text-align: center;
}

.preview-box {
    border: 1px solid #ddd;
    border-radius: 50%;
    overflow: hidden;
    display: inline-block;
    background: #f5f5f5;
}

.preview-box canvas {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

@media (max-width: 768px) {
    .cropper-container {
        flex-direction: column;
    }
}
</style>